﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using Jayden.Dll.Core.Extensions;
using Jayden.Dll.Web.Events;
using Jayden.Dll.Web.Helper;
using Jayden.Dll.Web.HtmlControls;

namespace Jayden.Dll.Web.Controls
{
	public class UploadForm : Form
	{
		public delegate void OnUploadSuccess(HttpHandlerContext context);
		public delegate void OnFilesSaved(HttpHandlerContext context);

		public class UploadCommandHandler : HttpCommandHandler
		{
			public UploadCommandHandler() : this("Upload") { }
			public UploadCommandHandler(string command)
				: base(command)
			{
				RegisterEvent("UploadSuccess");
			}
			public event OnUploadSuccess UploadSuccess { add { AddEvent<OnUploadSuccess>("UploadSuccess", value); } remove { RemoveEvent<OnUploadSuccess>("UploadSuccess", value); } }

			protected override void ProcessCommand(HttpHandlerContext context, string command)
			{

				Invoke("UploadSuccess", context);

			}
		}


		private Input m_File;
		private Button m_Upload;
		private Ul m_List;
		private Progress m_Progress;

		public override void Load(System.Xml.XmlNode node, HtmlControlLoader loader)
		{
			base.Load(node, loader);

			if (Id == null)
				Id = "uploadForm";
			m_File = GetFormElement<Input>("file", true, true);
			m_Upload = GetFormElement<Button>("upload", "command");
			m_List = GetElementByServerId<Ul>("list", true);
			m_Progress = GetElementByServerId<Progress>("progress", true);
		}

		public override void ProcessHtmlRequest(HttpHandlerContext context)
		{
			UploadCommandHandler uploadHandler = context.HandlerManager.GetHandler<UploadCommandHandler>();
			uploadHandler.UploadSuccess += new OnUploadSuccess(UploadSuccess);
			base.ProcessHtmlRequest(context);
		}

		public bool ServerSaveFiles { get { return GetServerAttribute("save-files", "true") == "true"; } set { SetServerAttribute("save-file", value ? null : "false"); } }
		public string ServerSaveDirectory { get { return GetServerAttribute("save-directory", "/Uploads/"); } set { SetServerAttribute("save-directory", value); } }

		public event OnFilesSaved FilesSaved;

		void UploadSuccess(HttpHandlerContext context)
		{
			bool saveFiles = ServerSaveFiles;
			if (saveFiles)
			{
				string savePath = ServerSaveDirectory;
				string physicalDirectory = context.MapPath(savePath);
				string timeStamp = HtmlHelper.ToHtmlDateTime(DateTime.Now).Replace(':', '-');
				if (!Directory.Exists(physicalDirectory))
					Directory.CreateDirectory(physicalDirectory);
				Dictionary<string, HttpPostedFile> files = new Dictionary<string, HttpPostedFile>();
				List<string> virtualPaths = new List<string>();
				m_List.Clear();
				m_List.Classes.Add("uploaded");
				for (int c = 0; c < context.Request.Files.Count; c++)
				{
					HttpPostedFile postedFile = context.Request.Files[c];
					string filename = /*timeStamp + "." +*/ Path.GetFileName(postedFile.FileName);
					string filePhysicalPath = (physicalDirectory + "\\" + filename).Replace("\\\\","\\");
					postedFile.SaveAs(filePhysicalPath);
					files.Add(filePhysicalPath, postedFile);
					virtualPaths.Add((savePath + "/" + filename).Replace("//","/"));
					Li li = m_List.AddLi();
					li.AddText<Span>(Path.GetFileName(postedFile.FileName)).Class = "name";
					li.AddText(" (");
					li.AddText<Span>(postedFile.ContentType).Class = "type";
					li.AddText(") ");
					li.AddText<Span>(StringExtensions.ToUserFriendlyByteLength((ulong)postedFile.ContentLength)).Class = "size";
					li.AddText(" ");
					A a = li.AddA("here", (savePath + "/" + filename).Replace("//", "/"));
					a.Target = "_blank";
					a.Class = "uploaded";
				}
				if (FilesSaved != null)
					FilesSaved(context);
				if (context.Json != null)
				{
					context.Json.Add("saveAs", virtualPaths);
				}
			}
		}

		public override void ProcessJsonRequest(HttpHandlerContext context)
		{
			UploadCommandHandler uploadHandler = context.HandlerManager.GetHandler<UploadCommandHandler>();
			uploadHandler.UploadSuccess += new OnUploadSuccess(UploadSuccess);

		}

		public override void ProcessJsRequest(HttpHandlerContext context)
		{
			base.ProcessJsRequest(context);

			string id = Id;
			context.Js[id].AppendAjaxHandler(@"
		if(data.saveAs) {
			var $tmp = $('#" + m_List.Id + @" > li');
			var inc;
			if((data.saveAs.length + 1) === $tmp.length) {
				for(inc=0;inc<data.saveAs.length;inc++) {
					$($tmp[inc]).append(' <a class=""uploaded"" target=""_blank"" href=""' + data.saveAs[inc] + '"">here</a>');
				}
			}
		}
");
			context.Js[id].AppendOnInit(@"
	var $uploadFile = $('#" + m_File.Id + @"');
	var $uploadForm = $('#" + Id + @"');
	var $upload = $('#" + m_Upload.Id + @"');
	var $fileList = $('#" + m_List.Id + @"');
	var $fileProgress = $('#" + m_Progress.Id + @"');

	// this should only be done if all event are handled ...
	$upload.attr('disabled', 'disabled');

	$uploadFile.change(function() {
		$fileProgress.attr('value', 0);
		var files = $uploadFile[0].files;
		var items = [];
		if(!files) {
			items.push('<span class=""name"">' + $uploadFile.val() + '</span>');
			$upload.removeAttr('disabled');
		} else {
			var idx = 0;
			var totalSize = 0;
			for(;idx<files.length;idx++)
			{
				var file = files[idx];
				items.push('<span class=""name"">' + file.name + '</span> (<span class=""type"">' + file.type + '</span>) <span class=""size"">' + JAYDEN.sfn.toUserFriendlyByteLength(file.size) + '</span>');
				totalSize += file.size;
			}
			if(files.length > 0) {
				items.push('Total size: ' + JAYDEN.sfn.toUserFriendlyByteLength(totalSize));
				$upload.removeAttr('disabled');
			}
			if(files.length === 0) {
				items.push('No file selected');
				$upload.attr('disabled', 'disabled');
			}
		}
		$fileList.html('<li>' + items.join('</li><li>') + '</li>');
		$fileList.removeClass('complete');
		$fileList.removeClass('uploading');
	});

	var uploadProgress = function(e) {
		if (e.lengthComputable) {
			var percentComplete = Math.round(e.loaded * 100 / e.total);
			$fileProgress.html(percentComplete.toString() + '%').attr('value', percentComplete);
		} else {
			$fileProgress.html('unable to compute');
		}
	};
	var uploadComplete = function(e) {
		//text of response : e.target.responseText;
		try {
			// try to create a json object with the response
			var data = jQuery.parseJSON(e.target.responseText);
			// to use the common success handler
			JAYDEN.sfn.successAjax(data);
		} catch (err) {
			alert('Upload complete.');
		}
		$fileList.addClass('complete');
		$fileList.removeClass('uploading');
		$uploadFile.removeAttr('disabled');
	}
	var uploadFailed = function(e) {
		alert('There was an error attempting to upload the file.');
	};
	var uploadCanceled = function(e) {
		alert('The upload has been canceled by the user or the browser dropped the connection.');
	};

	$uploadForm.submit(function(e) {
		var values = $uploadForm.serializeArray();
		var files = $uploadFile[0].files;
		if(!files)
			return true;
		var idx = 0;
		for(;idx<files.length;idx++)
			values.push({name: $uploadFile.attr('name') + '.files[' + idx + ']', value: files[idx] });
		values.push({name: $uploadFile.attr('name') + '.files.length', value: files.length });
		values.push({name: 'format', value: 'json' });
		values.push({name: 'command', value: $upload.val() });

		if(!JAYDEN.sfn.submitAjaxFormData(values, $uploadForm.attr('action'), $uploadForm.attr('method'), uploadProgress, uploadComplete, uploadFailed, uploadCanceled)) {
			$uploadFile.attr('disabled', 'disabled');
			$upload.attr('disabled', 'disabled');
			$fileList.addClass('uploading');
			// avoid standard form sending
			e.preventDefault();
			return false;
		} else {
			return true;
		}
	});
");
		}
	}
}
